import { ElMessage } from "element-plus";
import { isEqual, differenceWith } from "lodash";
import defaultPng from "/@/assets/images/map/default.png";
import startPng from "/@/assets/images/map/start.png";
import endPng from "/@/assets/images/map/end.png";
import carPng from "/@/assets/images/map/car.png";
import modelStartPng from "/@/assets/images/map/model_start.png";
import modelEndPng from "/@/assets/images/map/model_end.png";
import ambulance2dPng from "/@/assets/images/map/ambulance_2d.png";
import ambulance2d1Png from "/@/assets/images/map/ambulance_2d_1.png";
import ambulance3dPng from "/@/assets/images/map/ambulance_3d.png";
import ambulance3d1Png from "/@/assets/images/map/ambulance_3d_1.png";
import moveCarPng from "/@/assets/images/map/move_car.png";
import moveAmbulance1Png from "/@/assets/images/map/move_ambulance_1.png";
import moveAmbulance2Png from "/@/assets/images/map/move_ambulance_2.png";

// 获取腾讯地图API对象
const TMap = window.TMap;
if (!TMap) ElMessage.error("地图资源加载失败，请关闭浏览器的广告拦截功能");

// 初始化地图并挂载至页面上
export function createMap(sLat: number, sLng: number, eLat?: number, eLng?: number, DOM_ID = "mapContainer") {
	// 创建中心坐标实例(根据起点和终点计算得出)
	let cLat = eLat != undefined ? (sLat + eLat) / 2 : sLat;
	let cLng = eLng != undefined ? (sLng + eLng) / 2 : sLng;
	const centerLoc = new TMap.LatLng(cLat, cLng);
	return new TMap.Map(document.getElementById(DOM_ID), {
		center: centerLoc,
		zoom: 16, // 地图的缩放级别
		// pitchable: false, // 是否允许设置俯仰角度
	});
}

// 解析路线规划数据(折线数据)
export function analyseRoute(polyline: number[]) {
	const coords = [polyline[0], polyline[1]];
	const coordInstances = [];
	// 解压点串坐标数组 coords（因为服务器返回的点串坐标会通过前向差分算法进行压缩）
	for (let i = 2; i < polyline.length; i++) {
		coords[i] = Number(coords[i - 2]) + Number(polyline[i]) / 1000000;
	}
	// 将解压后的坐标转化为 LatLng 实例再放入点坐标实例数组 coordInstances 中
	for (let i = 0; i < coords.length; i += 2) {
		coordInstances.push(new TMap.LatLng(coords[i], coords[i + 1]));
	}
	return coordInstances;
}

// 在地图上渲染 Path 数据(折线数据)
export function createPath(coordInstances: EmptyArrayType[], map: any, isDual = false) {
	const geometriesArray = [
		{
			id: "path_unpassed", // 折线唯一标识（未行驶的路线）
			styleId: "style_blue", // 绑定样式名
			paths: coordInstances,
		},
	];
	if (isDual) {
		geometriesArray.push({
			id: "path_passed", // 折线唯一标识（已行驶的路线）
			styleId: "style_blue", // 绑定样式名
			paths: coordInstances,
		});
	}
	return new TMap.MultiPolyline({
		id: "polylineLayer", // 图层唯一标识
		map: map, // 绘制到目标地图
		// 折线样式定义
		styles: {
			style_blue: new TMap.PolylineStyle({
				color: "#3777FF", // 线填充色
				width: 7, // 折线宽度
				borderWidth: 3, // 边线宽度
				borderColor: "#FFF", // 边线颜色
				lineCap: "round", // 线端头方式
				showArrow: true,
			}),
			style_gray: new TMap.PolylineStyle({
				color: "#CCC", // 线填充色
				width: 7, // 折线宽度
				borderWidth: 3, // 边线宽度
				borderColor: "#FFF", // 边线颜色
				lineCap: "round", // 线端头方式
				showArrow: true,
			}),
		},
		// 折线数据定义
		geometries: geometriesArray,
	});
}
// 在地图上添加 Path 数据(折线数据)
export function addPath(pathId: string, styleId: string, coordInstances: EmptyArrayType[], polyline: any) {
	const addGeometries = [
		{
			id: pathId, // 折线唯一标识
			styleId: styleId, // 绑定样式名
			paths: coordInstances,
		},
	];
	polyline.add(addGeometries);
}

/**
 * 点标记对象
 * @param {*} src Image Module 通过 import 引入的图片文件
 * @param {*} width number 图片宽度
 * @param {*} height number 图片高度
 * @param {*} anchor { x: number, y: number} 焦点在图片中的像素位置
 */
const PointStyle = {
	default: {
		src: defaultPng,
		width: 34,
		height: 50,
		anchor: { x: 25, y: 47 },
	},
	start: {
		src: startPng,
		width: 30,
		height: 40,
		anchor: { x: 21, y: 37 },
	},
	end: {
		src: endPng,
		width: 30,
		height: 40,
		anchor: { x: 21, y: 37 },
	},
	car: {
		src: carPng,
		width: 30,
		height: 40,
		anchor: { x: 21, y: 37 },
	},
	model_start: {
		src: modelStartPng,
		width: 34,
		height: 50,
		anchor: { x: 20, y: 40 },
	},
	model_end: {
		src: modelEndPng,
		width: 34,
		height: 50,
		anchor: { x: 20, y: 40 },
	},
	ambulance_2d: {
		src: ambulance2dPng,
		width: 72,
		height: 36,
		anchor: { x: 36, y: 18 },
	},
	ambulance_2d_1: {
		src: ambulance2d1Png,
		width: 72,
		height: 36,
		anchor: { x: 36, y: 18 },
	},
	ambulance_3d: {
		src: ambulance3dPng,
		width: 50,
		height: 50,
		anchor: { x: 25, y: 25 },
	},
	ambulance_3d_1: {
		src: ambulance3d1Png,
		width: 60,
		height: 60,
		anchor: { x: 30, y: 30 },
	},
	move_car: {
		src: moveCarPng,
		width: 50,
		height: 50,
		anchor: { x: 25, y: 25 },
		faceTo: "map",
	},
	move_ambulance_1: {
		src: moveAmbulance1Png,
		width: 30,
		height: 60,
		anchor: { x: 15, y: 30 },
		faceTo: "map",
	},
	move_ambulance_2: {
		src: moveAmbulance2Png,
		width: 25,
		height: 60,
		anchor: { x: 13, y: 30 },
		faceTo: "map",
	},
};
// 在地图上渲染 Marker 数据(点标记数据)
export function createMarker(points: PointerType[], map: any) {
	const styles = {} as EmptyObjectType;
	const geometries = [] as EmptyArrayType;
	points.forEach(item => {
		item.pointType = item.pointType || "default";
		styles[item.pointType] = new TMap.MarkerStyle({
			...PointStyle[item.pointType],
			rotate: item.rotate || 0,
		});
		geometries.push({
			id: item.id,
			styleId: item.pointType,
			position: new TMap.LatLng(item.lat, item.lng),
			properties: item.properties,
		});
	});
	return new TMap.MultiMarker({
		id: "markerLayer",
		map: map,
		styles: styles,
		geometries: geometries,
	});
}
// 在地图上添加 Marker 数据(点标记数据)
export function addMarker(points: PointerType[], marker: any) {
	const addStyles = {} as EmptyObjectType;
	const addGeometries = [] as EmptyArrayType;
	points.forEach(item => {
		item.pointType = item.pointType || "default";
		addStyles[item.pointType] = new TMap.MarkerStyle({
			...PointStyle[item.pointType],
			rotate: item.rotate || 0,
		});
		addGeometries.push({
			id: item.id,
			styleId: item.pointType,
			position: new TMap.LatLng(item.lat, item.lng),
			properties: item.properties,
		});
	});
	marker.setStyles({
		...marker.getStyles(),
		...addStyles,
	});
	marker.add(addGeometries);
}
// 更新车辆 Marker 的位置
export function updateCarMarker(carPoints: PointerType[], coordInstances: EmptyArrayType[], marker: any) {
	// 比较 carPoints 和 coordInstances 的长度
	if (carPoints.length !== coordInstances.length) {
		return ElMessage.error("车辆位置更新失败，carPoints 和 coordInstances 的长度不一致");
	}
	// 更新 Marker 的位置
	const newGeometries = carPoints.map((item, index) => {
		return {
			id: item.id,
			styleId: item.pointType,
			position: coordInstances[index],
			properties: item.properties,
		};
	});
	marker.updateGeometries(newGeometries);
}
// 实现车辆 Marker 的行驶动画
export function moveCarMarker(
	carPoint: PointerType,
	newCoords: EmptyArrayType[],
	oldCoords: EmptyArrayType[],
	marker: any,
	polyline: any,
	duration = 3000
) {
	// 计算车辆 Marker 的朝向角度和两次车辆行驶轨迹的差值
	let roation = 0;
	let diffCoords: EmptyArrayType = [];
	if (oldCoords.length > 1) {
		roation = TMap.geometry.computeHeading(oldCoords[oldCoords.length - 2], oldCoords[oldCoords.length - 1]);
		diffCoords = differenceWith(newCoords, oldCoords, isEqual);
	} else {
		roation = TMap.geometry.computeHeading(newCoords[0], newCoords[1]);
		diffCoords = newCoords;
	}
	// 更新车辆 Marker 的朝向角度
	let myStyles = marker.getStyles();
	myStyles[carPoint.pointType!].rotate = 360 - roation;
	marker.setStyles(myStyles);
	// 更新车辆 Marker 的位置
	marker.updateGeometries([
		{
			id: carPoint.id,
			styleId: carPoint.pointType,
			position: oldCoords.length > 0 ? oldCoords[oldCoords.length - 1] : diffCoords[0],
			properties: carPoint.properties,
		},
	]);
	// 触发车辆行驶动画
	if (diffCoords.length > 0) {
		marker.moveAlong(
			{
				[carPoint.id]: {
					path: oldCoords.length > 0 ? [oldCoords[oldCoords.length - 1], ...diffCoords] : diffCoords,
					// duration: duration, // 单位: ms
					speed: 400, // 单位: km/h
				},
			},
			{ autoRotation: true }
		);
		// 监听车辆行驶动画的 moving 事件
		marker.on("moving", (e: any) => {
			// console.log("car moving", e);
			var passedLatLngs = e[carPoint.id] && e[carPoint.id].passedLatLngs;
			if (passedLatLngs) {
				// 使用 updateGeometries 更新已经走过的路线
				polyline.updateGeometries([
					{
						id: "path_passed",
						styleId: "style_gray",
						paths: [...oldCoords, ...passedLatLngs],
					},
				]);
			}
		});
		return new Promise<EmptyObjectType>(resolve => {
			// 监听车辆行驶动画的 move_ended 事件
			marker.on("move_ended", (e: any) => {
				resolve(e);
			});
		});
	} else {
		return Promise.resolve("No diffCoords");
	}
}

// 调整地图显示范围的参数
const fitPadding = {
	home: { top: 60, bottom: 50, left: 50, right: 100 }, // 首页
};
// 调整地图显示范围的方法
export function fitBounds(coordInstances: EmptyArrayType[], map: any, fitKey: string) {
	// 创建坐标范围 LatLngBounds 实例
	const latlngBounds = new TMap.LatLngBounds();
	// 把路线坐标作为参数逐一传入 extend 方法，即可扩展 latlngBounds 的范围
	for (let i = 0; i < coordInstances.length; i++) {
		latlngBounds.extend(coordInstances[i]);
	}
	// 调用地图 API fitBounds 即可调整地图的显示范围
	map.fitBounds(latlngBounds, { padding: fitPadding[fitKey] });
}

/**
 * 渲染地图 + 路线，一步到位
 * @param {*} p1 起点
 * @param {*} p2 终点
 * @param {*} polyline 点串坐标数组
 * @param {*} DOM_ID 挂载地图的DOM元素ID，默认"mapContainer"
 */
export function oneStepToMap(p1: PointerType, p2: PointerType, polyline: number[], DOM_ID = "mapContainer") {
	const coords = analyseRoute(polyline);
	const map = createMap(p1.lat, p1.lng, p2.lat, p2.lng, DOM_ID);
	const marker = createMarker([p1, p2], map);
	const polyLine = createPath(coords, map);
	return {
		coords,
		map,
		marker,
		polyLine,
	};
}
